use std::sync::mpsc::{Sender, Receiver};
use specs::{System, Entities, ReadStorage};
use specs::world::Index;
use crate::res::position_storage::Position;
use crate::res::minions_storage::Minions;

#[derive(Clone)]
pub struct QueryMinionsPositionStreamMessage
{
    to: Sender<Vec<(Index, Position)>>,
    who: Index,
}

impl QueryMinionsPositionStreamMessage
{
    pub fn new(to: Sender<Vec<(Index, Position)>>, who: Index) -> Self {
        QueryMinionsPositionStreamMessage {
            to,
            who,
        }
    }
}

pub struct QueryMinionsPositionStreamSystem
{
    rc: Receiver<QueryMinionsPositionStreamMessage>,
    streams: Vec<QueryMinionsPositionStreamMessage>,
}

impl QueryMinionsPositionStreamSystem
{
    pub fn new(rc: Receiver<QueryMinionsPositionStreamMessage>) -> Self {
        QueryMinionsPositionStreamSystem {
            rc,
            streams: Vec::new(),
        }
    }
}

impl<'a> System<'a> for QueryMinionsPositionStreamSystem
{
    type SystemData = (
        Entities<'a>,
        ReadStorage<'a, Position>,
        ReadStorage<'a, Minions>,
    );

    fn run(&mut self, data: Self::SystemData) {
        let (entities, position_storage, minions_storage) = data;

        if let Ok(report) = self.rc.try_recv() {
            self.streams.push(report);
        }

        let mut to_remove = Vec::new();

        for (i, stream) in self.streams.iter().enumerate() {
            let mut result = Vec::new();
            let who_entity = entities.entity(stream.who);

            if let Some(minions) = minions_storage.get(who_entity) {
                for minion_id in minions.0.iter() {
                    let minion = entities.entity(minion_id.clone());

                    if let Some(position) = position_storage.get(minion) {
                        result.push((minion_id.clone(), position.clone()));
                    }
                }
            }
            
            if let Err(_) = stream.to.send(result.clone()) {
                to_remove.push(i);
            }
        }

        for index in to_remove.iter() {
            self.streams.remove(index.clone());
        }
    }
}
